当使用函数模板(如max())时，模板参数由传入的参数决定。如果类型T传递两个int型参数，那编译器就会认为T是int型。

然而，T可能只是类型的“一部分”。若声明max()使用常量引用:

\begin{lstlisting}[style=styleCXX]
template<typename T>
T max (T const& a, T const& b)
{
	return b < a ? a : b;
}
\end{lstlisting}

并传递int，同样T会推导为int，因为函数形参匹配的是int const\&。

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{类型推导时的类型转换}

注意，自动类型转换在类型推导时有一些限制:

\begin{itemize}
\item
当通过引用声明参数时，简单的转换也不适用于类型推导。用同一个模板参数T声明的两个实参必须完全匹配。

\item
当按值声明参数时，只支持简单的转换:忽略const或volatile的限定符，引用转换为引用的类型，原始数组或函数转换为相应的指针类型。对于使用相同模板参数T声明的两个参数，转换类型必须匹配。
\end{itemize}

例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
T max (T a, T b);
...
int i = 17;
int const c = 42;
max(i, c); // OK: T推导为int
max(c, c); // OK: T推导为int
int& ir = i;
max(i, ir); // OK: T推导为int
int arr[4];
max(&i, arr); // OK: T推导为int*
\end{lstlisting}

下面就是反面案例了：

\begin{lstlisting}[style=styleCXX]
max(4, 7.2); // ERROR: T推导为int或double
std::string s;
max("hello", s); // ERROR: T推导为char const*或std::string
\end{lstlisting}

有三种方法可以处理此类错误:

\begin{enumerate}
\item
强制转换:
\begin{lstlisting}[style=styleCXX]
max(static_cast<double>(4), 7.2); // OK
\end{lstlisting}

\item
显式指定(或限定)T的类型:
\begin{lstlisting}[style=styleCXX]
max<double>(4, 7.2); // OK
\end{lstlisting}

\item
指定参数可以有不同的类型。
\end{enumerate}

第1.3节将进行详细的说明。第7.2节和第15章将详细讨论类型推导时的类型转换规则。

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{默认参数的类型推导}

类型推导不适用于默认调用参数。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void f(T = "");
...
f(1); // OK: 推导出T为int，因此其可以调用f<int>(1)
f(); // ERROR: 不能推断出T的类型
\end{lstlisting}

为了支持这种情况，必须为模板形参声明一个默认实参，这将在1.4节中进行详述:

\begin{lstlisting}[style=styleCXX]
template<typename T = std::string>
void f(T = "");
...
f(); // OK
\end{lstlisting}














